define('framework/areas/AreasModule', [
    'angular',
    'jquery',
    'framework/areas/AreaServiceConstructor',
    'framework/constant/KEYS',
    'css!../../../css/areas.css'
], function (angular, $, AreaServiceConstructor, KEYS) {
    return angular.module('AreasModule', [])
        .directive('gAreas', ['$compile', 'AreaService', 'Arrays', '$window', '$document', '$timeout', '$http', function ($compile, AreaService, Arrays, $window, $document, $timeout, $http) {
            var AreaGroup = {COMMON: 'common', PROVINCE: 'province', CITY: 'city', COUNTY: 'county'},
                AreasProto = Areas.prototype;
            var tmpl = '<div class="address-pup-box" ng-click="$event.stopPropagation()" ng-show="areas.showPanel === true"> <div class="address-slide" ng-show="areas.searching === true"> <ul> <li ng-repeat="area in areas.foundAreas" ng-click="areas.deepSelect($event, area.code)"><a href="javascript:void(0)">{{areas.getDisplayPath(area.code)}}</a></li> </ul> </div> <div class="address-box" ng-show="areas.selection === true"> <div class="address-title"><span class="hot-city-span" ng-class="{\'span-on\': areas.activeTab === \'common\'}" ng-click="areas.activeTab = \'common\'">热门城市</span> <span ng-class="{\'span-on\':areas.activeTab === \'province\'}" ng-click="areas.activeTab = \'province\'">省份</span> <span ng-class="{\'span-on\':areas.activeTab === \'city\', \'disable-btn\': areas.cityDisabled}" ng-click="areas.selectCityTab()">城市</span> <span class="last-child" ng-class="{\'span-on\':areas.activeTab === \'county\', \'disable-btn\': areas.cityDisabled || areas.countyDisabled}" ng-click="areas.selectCountyTab()">县区</span> </div> <div class="address-mian"> <!--热门城市tab--> <div class="hot-city address-tab clearfix" ng-show="areas.activeTab === \'common\'"> <dl> <!--class="address-list clearfix"--> <dd><a href="javascript:;" ng-repeat="area in areas.commonAreas" ng-class="{\'active\':areas.selectedArea.c === area.c}" ng-click="areas.deepSelect($event, area.c)">{{area.n}}</a></dd> </dl> </div> <!--省份tab--> <div class="province address-tab clearfix" ng-show="areas.activeTab === \'province\'"> <div class="list-arrow list-prev"><i class="list-arrow-icon iconfont icon-qiehuanqizuo" ng-click="areas.provinceGoPage(-1)"></i></div> <div class="province-list"> <dl class="clearfix" ng-repeat="provinceGroup in areas.provinceGroupPage"> <dt>{{provinceGroup.range}}</dt> <dd><a href="javascript:" ng-repeat="province in provinceGroup.provinces" ng-click="areas.select($event, province.c)">{{province.n}}</a></dd> </dl> </div> <div class="list-arrow list-next"><i class="list-arrow-icon iconfont icon-qiehuanqiyou" ng-click="areas.provinceGoPage(1)"></i></div> </div> <!--城市tab--> <div class="city address-tab clearfix" ng-show="areas.activeTab === \'city\'"> <div class="list-arrow list-prev"><i class="list-arrow-icon iconfont icon-qiehuanqizuo" ng-click="areas.cityGoPage(-1)"></i></div> <div class="city-list"> <dl> <dd><a href="javascript:;" ng-repeat="city in areas.cities" ng-class="{\'active\':areas.selectedArea.c === city.c}" ng-click="areas.select($event, city.c)">{{city.n}}</a></dd> </dl> </div> <div class="list-arrow list-next"><i class="list-arrow-icon iconfont icon-qiehuanqiyou" ng-click="areas.cityGoPage(1)"></i></div> </div> <!--区县tab--> <div class="county address-tab clearfix" ng-show="areas.activeTab === \'county\'"> <div class="list-arrow list-prev"><i class="list-arrow-icon iconfont icon-qiehuanqizuo" ng-click="areas.countyGoPage(-1)"></i></div> <div class="county-list"> <dl> <dd><a href="javascript:;" ng-repeat="county in areas.counties" ng-class="{\'active\':areas.selectedArea.c === county.c}" ng-click="areas.select($event, county.c)">{{county.n}}</a></dd> </dl> </div> <div class="list-arrow list-next"><i class="list-arrow-icon iconfont icon-qiehuanqiyou" ng-click="areas.countyGoPage(1)"></i></div> </div> </div> </div> </div>';

            /**
             *
             * @param params Areas 构造函数的构造参数
             * @param params Areas.scope {Object} 构造函数的构造参数
             * @param params Areas.attrs {Object} 构造函数的构造参数
             * @param params Areas.element {HTMLInputElement} 构造函数的构造参数
             * @param params [Areas.ngModelController] {ngModelController} 构造函数的构造参数
             *
             * @constructor
             */
            function Areas(params) {
                var me = this,
                    element = params.element,
                    ngModelController = params.ngModelController,
                    provinceGroupPages = AreaService.getProvinceGroupPages();
                me.scope = params.scope;
                me.ngModelController = ngModelController;
                me.element = element;
                me.attrs = params.attrs;


                me.cityDisabled = true;
                //noinspection JSUnusedGlobalSymbols
                me.activeTab = AreaGroup.COMMON;
                //noinspection JSUnusedGlobalSymbols
                me.showPanel = false;

                me.commonAreas = AreaService.getCommonAreas();

                ngModelController.$render = function (rawValue) {
                    var value = rawValue || ngModelController.$viewValue,
                        display,
                        scope = me.scope,
                        area = AreaService.findArea(value);
                    if (value) {
                        display = me.getDisplay(value);
                        element.val(display);
                        //如果控件有绑定选中地区
                        if (!!params.attrs.selectedArea && scope.$selectedArea !== area) {
                            scope.$selectedArea = area;
                        }
                    } else {
                        element.val('');
                    }
                };

                me.provincePageNumber = 1;
                me.cityPageNumber = 1;
                me.countyPageNumber = 1;

                me.provinceGroupPage = provinceGroupPages[0];
            }

            AreasProto.provinceGoPage = function (step) {
                var me = this,
                    provinceGroupPages = AreaService.getProvinceGroupPages(),
                    totalPage = provinceGroupPages.length,
                    page = me.provincePageNumber,
                    targetPage = page + step


                if (targetPage >= 1 && targetPage <= totalPage) {
                    me.provincePageNumber = targetPage;
                    me.provinceGroupPage = provinceGroupPages[me.provincePageNumber - 1];
                }
            };

            AreasProto.cityGoPage = function (step) {
                var me = this,
                    allCities = me.allCities,
                    len = allCities.length,
                    page = me.cityPageNumber,
                    targetPage = page + step,
                    totalPage = Math.ceil(len / 16),
                    start, end;


                if (targetPage >= 1 && targetPage <= totalPage) {
                    me.cityPageNumber = targetPage;
                    start = (targetPage - 1) * 16;
                    end = Math.min(start + 16, len);
                    me.cities = allCities.slice(start, end);
                }
            };

            AreasProto.countyGoPage = function (step) {
                var me = this,
                    allCounties = me.allCounties,
                    len = allCounties.length,
                    page = me.countyPageNumber,
                    targetPage = page + step,
                    totalPage = Math.ceil(len / 16),
                    start, end;


                if (targetPage >= 1 && targetPage <= totalPage) {
                    me.countyPageNumber = targetPage;
                    start = (targetPage - 1) * 16;
                    end = Math.min(start + 16, len);
                    me.counties = allCounties.slice(start, end);
                }
            };


            AreasProto.select = function ($event, areaCode) {
                var scope = this.scope,
                    selectParams = {$event: $event, code: areaCode, area: AreaService.findArea(areaCode)},
                    onBeforeSelect = scope.onBeforeSelect || angular.noop,
                    onSelect = scope.onSelect || angular.noop;

                if (AreaService.isProvinceCode(areaCode)) {
                    selectParams.group = AreaGroup.PROVINCE;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        this.selectProvince();
                        if (scope.allowChooseProvince === 'true') {
                            this.renderArea();
                        }
                    }
                } else if (AreaService.isCityCode(areaCode)) {
                    selectParams.group = AreaGroup.CITY;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        this.selectCity();
                        if (scope.allowChooseCity === 'true') {
                            this.renderArea();
                        }
                    }
                } else { // 不是 province 不是 city 那就是 county
                    selectParams.group = AreaGroup.COUNTY;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        this.selectCounty();
                        this.renderArea();
                    }
                }
                onSelect(selectParams);
            };

            AreasProto.selectProvince = function (province) {
                var me = this,
                    selectedProvince = province || me.selectedArea,
                    provinceCode = selectedProvince.code;
                //noinspection JSUnusedGlobalSymbols
                me.allCities = AreaService.getAreaChildren(provinceCode);
                if (!(angular.isArray(me.allCities) && me.allCities.length > 0)) {
                    this.renderArea();
                    return;
                }
                me.cityGoPage(0);

                me.cityDisabled = false;
                me.countyDisabled = true;
                //noinspection JSUnusedGlobalSymbols
                me.allCounties = undefined;
                //noinspection JSUnusedGlobalSymbols
                me.activeTab = AreaGroup.CITY;
                me.selectedProvince = selectedProvince;
                me.selectedCity = undefined;
                me.selectedCounty = undefined;
            };

            AreasProto.selectCity = function (city) {
                var me = this,
                    selectedCity = city || me.selectedArea,
                    cityCode = selectedCity.code;
                //noinspection JSUnusedGlobalSymbols
                me.allCounties = AreaService.getAreaChildren(cityCode);
                me.countyGoPage(0);

                me.countyDisabled = false;
                //noinspection JSUnusedGlobalSymbols
                me.activeTab = AreaGroup.COUNTY;
                me.selectedCity = selectedCity;
                me.selectedCounty = undefined;
            };

            AreasProto.selectCounty = function () {
                var selectedCounty = this.selectedArea;
                //noinspection JSUnusedGlobalSymbols
                this.showPanel = false;
                this.selectedCounty = selectedCounty;
            };

            /**
             * 逐层选择地区， 例如如果选择市， 也将选择市所在的省
             * @param $event {Event} 事件对象
             * @param areaCode {String} 地区编号
             */
            AreasProto.deepSelect = function ($event, areaCode) {
                var scope = this.scope,
                    selectParams = {$event: $event, code: areaCode, area: AreaService.findArea(areaCode)},
                    onBeforeSelect = scope.onBeforeSelect || angular.noop,
                    onSelect = scope.onSelect || angular.noop,
                    province, city;

                if (AreaService.isProvinceCode(areaCode)) {
                    selectParams.group = AreaGroup.PROVINCE;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        this.selectProvince();
                    }
                } else if (AreaService.isCityCode(areaCode)) {
                    selectParams.group = AreaGroup.CITY;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        province = AreaService.findProvince(areaCode);
                        this.selectProvince(province);
                        this.selectCity();
                    }
                } else {
                    selectParams.group = AreaGroup.COUNTY;
                    if (onBeforeSelect(selectParams) !== false) {
                        this.selectedArea = selectParams.area;
                        province = AreaService.findProvince(areaCode);
                        this.selectProvince(province);
                        city = AreaService.findCity(areaCode);
                        this.selectCity(city);
                        this.selectCounty();
                    }
                }

                this.searching=false;
                this.selection = true;
                this.renderArea();
                onSelect(selectParams);
            };


            /**
             * @private 转化当前地区数据到视图
             */
            AreasProto.renderArea = function () {
                var me = this,
                    element = me.element,
                    attrs = me.attrs,
                    scope = me.scope,
                    ngModelController = me.ngModelController;

                me.renderedArea = me.selectedArea;

                if (me.renderedArea) {
                    if (angular.isDefined(ngModelController)) {
                        ngModelController.$setViewValue(me.renderedArea.code);
                        ngModelController.$render();
                    } else {
                        element.val(me.getDisplay());
                    }

                    //如果控件有绑定选中地区
                    if (!!attrs.selectedArea && scope.$selectedArea !== me.renderedArea) {
                        scope.$selectedArea = me.renderedArea;
                    }
                }

            };

            function getAreaDeepPath(areaCode) {
                var areaPaths = [],
                    province, city, county;
                province = AreaService.findProvince(areaCode);
                if (province) {
                    areaPaths.push(province);
                    city = AreaService.findCity(areaCode);
                    if (city) {
                        areaPaths.push(city);
                        county = AreaService.findCounty(areaCode);
                        if (county) {
                            areaPaths.push(county);
                        }
                    }

                }
                return areaPaths;
            }

            /**
             * @public
             * @return {String} 显示在文本框中的信息
             */
            AreasProto.getDisplay = function (areaCode) {
                var scope = this.scope,
                    isDisplayPath = angular.isDefined(scope.isDisplayPath) ? scope !== 'false' : true,
                    pathSeparator = scope.pathSeparator || '/',
                    areaDeepPath = getAreaDeepPath(areaCode);

                if (isDisplayPath) {
                    return Arrays.extract(areaDeepPath, 'name').join(pathSeparator);
                } else if (areaDeepPath.length > 0) {
                    return areaDeepPath[areaDeepPath.length - 1].name;
                }
            };

            //noinspection JSUnusedGlobalSymbols
            AreasProto.getDisplayPath = function (areaCode) {
                var province = AreaService.findProvince(areaCode),
                    city = AreaService.findCity(areaCode),
                    county = AreaService.findCounty(areaCode),
                    areas = [province, city, county],
                    pathSeparator = this.scope.pathSeparator || '/';

                return Arrays.extract(areas, 'name').join(pathSeparator);
            };


            //noinspection JSUnusedGlobalSymbols
            /**
             * @private 选择城市tab页
             */
            AreasProto.selectCityTab = function () {
                if (this.cityDisabled !== true) {
                    //noinspection JSUnusedGlobalSymbols
                    this.activeTab = AreaGroup.CITY;
                }
            };

            //noinspection JSUnusedGlobalSymbols
            /**
             * @private 选择区县tab页
             */
            AreasProto.selectCountyTab = function () {
                if (!(this.cityDisabled === true || this.countyDisabled === true)) {
                    //noinspection JSUnusedGlobalSymbols
                    this.activeTab = AreaGroup.COUNTY
                }
            };

            AreasProto.search = function () {
                var me = this,
                    scope = me.scope,
                    element = me.element,
                    keyword = element.val();
                if (!!$.trim(keyword)) {
                    me.showPanel = false;
                    me.selection = false;
                    me.searching = true;
                    if (me.reSearchTimer) {
                        $timeout.cancel(me.reSearchTimer);
                        me.reSearchTimer = undefined;
                    }
                    me.reSearchTimer = $timeout(function () {
                        scope.$keyword = keyword;
                        $http.get($window.basePath + '/areas/search?keyword=' + scope.$keyword)
                            .success(function (data) {
                                if (angular.isArray(data)){
                                    me.showPanel = true;
                                    me.foundAreas = data;
                                }
                            });
                    }, 300);
                }
            };

            AreasProto.resetCity = function () {
                this.cities = undefined;
                this.cityPageNumber = 1;
                this.counties = undefined;
                this.countyPageNumber = 1;
                this.countyDisabled = true;
            };

            AreasProto.resetCounty = function () {
                this.counties = undefined;
                this.countyPageNumber = 1;
            };

            AreasProto.hoverArea = function (add) {
                var hoveredIndex = me.hoveredIndex || 0;
                switch (this.activeTab) {
                    case 'province':
                        var allProvince = AreaService.getAllProvince();

                        break;
                }
            };

            return {
                restrict: 'A',
                scope: {
                    /**
                     * @param arg
                     * @param arg.$event 事件对象
                     * @param arg.code 地区编号
                     * @param arg.area 地区实例
                     * @param arg.group {AreaGroup} 地区分组
                     * @return {false|*} 为 false 将终止操作
                     */
                    onBeforeSelect: '&',
                    /**
                     * @param arg
                     * @param arg.$event 事件对象
                     * @param arg.code 地区编号
                     * @param arg.area 地区实例
                     * @param arg.group {AreaGroup} 地区分组
                     */
                    onSelect: '&',
                    $selectedArea:'=selectedArea',
                    $areas: '=api',
                    allowChooseCity: '@',
                    allowChooseProvince: '@',
                    isDisplayPath: '@',
                    pathSeparator: '@'
                },
                require: '?ngModel',
                link: function (scope, element, attrs, ngModelController) {

                    var areas = scope.areas = new Areas({
                            scope: scope,
                            element: element,
                            attrs: attrs,
                            ngModelController: ngModelController
                        }),
                        $elementPosition = element.position();

                    function modelValueChange(rawValue) {
                        if (AreaService.isAreaCode(rawValue)) {
                            ngModelController.$render(rawValue);
                            return rawValue;
                        }else {
                            areas.search();
                        }
                    }

                    ngModelController.$formatters.push(modelValueChange);
                    ngModelController.$parsers.push(modelValueChange);

                    if (!!attrs.api) {
                        scope.$areas = areas;
                        console.log('defined api')
                    }
                    var areaPanel = $compile(tmpl)(scope);
                    element.after(areaPanel);


                    element.on('focus', function () {
                        if (element.attr('disabled') || element.hasClass('disabled')) return;

                        areaPanel.css({
                            top: $elementPosition.top + element.outerHeight(),
                            left: $elementPosition.left
                        });
                        areas.showPanel = true;
                        areas.searching = false;
                        areas.selection = true;
                        scope.$digest();
                        $timeout(function () {
                            element.select();
                        }, 0);
                    });

                    /*element.on('keydown', function (event) {
                        if (event.keyCode === KEYS.DOWN && areas.showPanel === false) {
                            areas.showPanel = true;
                            areas.selection = true;
                        } else if (event.keyCode === KEYS.DOWN && areas.showPanel === true) {
                            areas.hoverArea(+4);
                        } else if (event.keyCode === KEYS.UP && areas.showPanel === true) {
                            areas.hoverArea(-4);
                        } else if (event.keyCode === KEYS.LEFT && areas.showPanel === true) {
                            areas.hoverArea(-1);
                        } else if (event.keyCode === KEYS.LEFT && areas.showPanel === true) {
                            areas.hoverArea(+1);
                        }
                        scope.$digest();
                    });*/

                    element.on('change', function (event) {
                        areas.showPanel = false;
                        areas.selection = false;
                        areas.searching = true;
                        areas.search();
                    });

                    element.blur(function () {
                        // reset on manual change display
                        if (ngModelController && areas.getDisplay(ngModelController.$viewValue) !== element.val()) {
                            ngModelController.$setViewValue(undefined);
                            ngModelController.$render();
                        }
                    });

                    $document.on('click', function (event) {
                        event = event || $window.event;
                        var target = event.target || event.srcElement;
                        if (!element.is(target)) {
                            areas.showPanel = false;
                            scope.$digest();
                        }
                    });
                    $($window).on('resize', function () {
                        areaPanel.css({
                            top: $elementPosition.top + element.outerHeight(),
                            left: $elementPosition.left
                        });
                    });
                }
            };
        }])
        .factory('AreaService', ['Arrays', 'Predicates', AreaServiceConstructor]);
});